package de.ifi.lmu.snitzelhunt.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.os.AsyncTask;
import android.util.Log;
import de.ifi.lmu.snitzelhunt.basics.Route;
import de.ifi.lmu.snitzelhunt.basics.User;
import de.ifi.lmu.snitzelhunt.util.basics.RouteInfoContainer;
import de.ifi.lmu.snitzelhunt.util.responses.AsyncServer_RouteInfo_ReadforCreatorResponse;
import de.ifi.lmu.snitzelhunt.util.responses.AsyncServer_RouteInfo_ReadforUserResponse;
import de.ifi.lmu.snitzelhunt.util.responses.AsyncServer_Route_CreateResponse;
import de.ifi.lmu.snitzelhunt.util.responses.AsyncServer_Route_DeleteResponse;
import de.ifi.lmu.snitzelhunt.util.responses.AsyncServer_Route_ReadResponse;
import de.ifi.lmu.snitzelhunt.util.responses.AsyncServer_Route_UpdateResponse;
import de.ifi.lmu.snitzelhunt.util.responses.Server_RouteInfo_ReadforCreatorResponse;
import de.ifi.lmu.snitzelhunt.util.responses.Server_RouteInfo_ReadforUserResponse;
import de.ifi.lmu.snitzelhunt.util.responses.Server_Route_CreateResponse;
import de.ifi.lmu.snitzelhunt.util.responses.Server_Route_DeleteResponse;
import de.ifi.lmu.snitzelhunt.util.responses.Server_Route_ReadResponse;
import de.ifi.lmu.snitzelhunt.util.responses.Server_Route_UpdateResponse;

/**
 * Utilities for handling operations on the remote mySQL database via HTTP POST
 * requests
 * 
 * @author jaschkowitz
 * 
 */
public class RouteServerUtility {

	/**
	 * Method to download a Route from the mySQL Server. An AsyncTask is used to
	 * start a new thread outside of the UI Thread.
	 * {@link AsyncServer_Route_ReadResponse} target is used for the caller to
	 * get the response from the Server
	 * 
	 * @param globalID
	 * @param target
	 */
	public void readRoute(long globalID, AsyncServer_Route_ReadResponse target) {
		new ReadRouteTask(target).execute(globalID);
	}

	/**
	 * Method to upload a Route to the mySQL Server. An AsyncTask is used to
	 * start a new thread outside of the UI Thread.
	 * {@link AsyncServer_Route_CreateResponse} target is used for the caller to
	 * get the response from the Server
	 * 
	 * 
	 * @param r
	 * @param target
	 */
	public void createRoute(Route r, AsyncServer_Route_CreateResponse target) {
		new UploadTask(target).execute(r);
	}

	/**
	 * Method to download a Route from the mySQL Server. An AsyncTask is used to
	 * start a new thread outside of the UI Thread.
	 * {@link AsyncServer_Route_ReadResponse} target is used for the caller to
	 * get the response from the Server
	 * 
	 * @param globalID
	 * @param target
	 */
	public void updateRoute(Route r, AsyncServer_Route_UpdateResponse target) {
		new UpdateTask(target).execute(r);
	}

	/**
	 * Method to download a Route from the mySQL Server. An AsyncTask is used to
	 * start a new thread outside of the UI Thread.
	 * {@link AsyncServer_Route_ReadResponse} target is used for the caller to
	 * get the response from the Server
	 * 
	 * @param globalID
	 * @param target
	 */
	public void deleteRoute(long globalID,
			AsyncServer_Route_DeleteResponse target) {
		new DeleteRouteTask(target).execute(globalID);
	}

	/**
	 * Method to get information of all Routes on the mySQL Server where the
	 * user is a participant. An AsyncTask is used to start a new thread outside
	 * of the UI Thread. {@link AsyncServer_Route_CreateResponse} target is used
	 * for the caller to get the response from the Server
	 * 
	 * 
	 * @param r
	 * @param target
	 */
	public void readRouteInfo_forUser(User u,
			AsyncServer_RouteInfo_ReadforUserResponse target) {
		new RouteInfoReadforUserTask(target).execute(u);
	}

	/**
	 * Method to get information of all Routes on the mySQL Server where the
	 * creator is the Creator. An AsyncTask is used to start a new thread
	 * outside of the UI Thread. {@link AsyncServer_Route_CreateResponse} target
	 * is used for the caller to get the response from the Server
	 * 
	 * 
	 * @param r
	 * @param target
	 */
	public void readRouteInfo_forCreator(String creator,
			AsyncServer_RouteInfo_ReadforCreatorResponse target) {
		new RouteInfoReadforCreatorTask(target).execute(creator);
	}

	/**
	 * AsyncTask to download a Route from the remote mySQL Database.
	 * 
	 * @author jaschkowitz
	 * 
	 */
	private class ReadRouteTask extends
			AsyncTask<Long, Void, Server_Route_ReadResponse> {
		private AsyncServer_Route_ReadResponse target;

		private ReadRouteTask(AsyncServer_Route_ReadResponse targetAct) {
			super();
			target = targetAct;
		}

		@Override
		protected Server_Route_ReadResponse doInBackground(Long... globalID) {
			InputStream connIS = null;
			OutputStream connOS = null;
			HttpURLConnection conn = null;
			Server_Route_ReadResponse resp = new Server_Route_ReadResponse();

			try {
				// Setup for the Connection
				URL url = new URL(
						"http://141.84.213.225:8080/MSP/downloadRoute");
				conn = ConnectionHelper.setupHttpConnection(url);

				// Connect
				conn.connect();

				// post global RouteID to Server
				String json = GSonUtility.serializeLong(globalID[0]);
				connOS = conn.getOutputStream();
				ConnectionHelper.writeString(connOS, json);
				Log.i("snitzelhunt util", "POST read Route to URL : " + url);
				Log.i("snitzelhunt util",
						"Response Code : " + conn.getResponseCode());

				// get Server Response
				if (conn.getResponseCode() == 200) { // succesful
					// read Server Response
					connIS = conn.getInputStream();
					String recv = ConnectionHelper.readResponse(connIS);

					// handle Reesponse=> Route
					Route recRoute = GSonUtility.deserializeRoute(recv);
					resp.setRecvRoute(recRoute);
				}
				resp.setHttpStatus(conn.getResponseCode());
				return resp;
			} catch (IOException e) {
				ConnectionHelper.handleIOException(e);
			} finally {
				ConnectionHelper.cleanConnection(connIS, connOS, conn);
			}

			resp.setHttpStatus(-1);
			return resp;
		}

		protected void onPostExecute(Server_Route_ReadResponse result) {
			target.processServer_Route_Read(result);
		}
	}

	/**
	 * AsyncTask to delete a Route from the remote mySQL Database.
	 * 
	 * @author jaschkowitz
	 * 
	 */
	private class DeleteRouteTask extends
			AsyncTask<Long, Void, Server_Route_DeleteResponse> {
		private AsyncServer_Route_DeleteResponse target;

		private DeleteRouteTask(AsyncServer_Route_DeleteResponse targetAct) {
			super();
			target = targetAct;
		}

		@Override
		protected Server_Route_DeleteResponse doInBackground(Long... globalID) {
			InputStream connIS = null;
			OutputStream connOS = null;
			HttpURLConnection conn = null;
			Server_Route_DeleteResponse resp = new Server_Route_DeleteResponse();

			try {
				// Setup for the Connection
				URL url = new URL("http://141.84.213.225:8080/MSP/deleteRoute");
				conn = ConnectionHelper.setupHttpConnection(url);

				// Connect
				conn.connect();

				// post global RouteID to Server
				connOS = conn.getOutputStream();
				String json = GSonUtility.serializeLong(globalID[0]);
				ConnectionHelper.writeString(connOS, json);

				Log.i("snitzelhunt util", "POST delete Route to URL : " + url);
				Log.i("snitzelhunt util",
						"Response Code : " + conn.getResponseCode());

				resp.setHttpStatus(conn.getResponseCode());
				return resp;

			} catch (IOException e) {
				ConnectionHelper.handleIOException(e);
			} finally {
				ConnectionHelper.cleanConnection(connIS, connOS, conn);
			}

			resp.setHttpStatus(-1);
			return resp;
		}

		protected void onPostExecute(Server_Route_DeleteResponse result) {
			target.processServer_Route_Delete(result);
		}
	}

	/**
	 * AsyncTask to get information about Routes from the remote mySQL Database.
	 * 
	 * @author jaschkowitz
	 * 
	 */
	private class RouteInfoReadforUserTask extends
			AsyncTask<User, Void, Server_RouteInfo_ReadforUserResponse> {
		private AsyncServer_RouteInfo_ReadforUserResponse target;

		private RouteInfoReadforUserTask(
				AsyncServer_RouteInfo_ReadforUserResponse targetAct) {
			super();
			target = targetAct;
		}

		@Override
		protected Server_RouteInfo_ReadforUserResponse doInBackground(
				User... user) {
			InputStream connIS = null;
			OutputStream connOS = null;
			HttpURLConnection conn = null;
			Server_RouteInfo_ReadforUserResponse resp = new Server_RouteInfo_ReadforUserResponse();

			try {
				// Setup for the Connection
				URL url = new URL("http://141.84.213.225:8080/MSP/getUserRoute");
				conn = ConnectionHelper.setupHttpConnection(url);

				// Connect
				conn.connect();

				// post Userdata to Server
				connOS = conn.getOutputStream();
				String str = user[0].getCellNumber();
				ConnectionHelper.writeString(connOS, str);

				Log.i("snitzelhunt util", "POST read routeinfo to URL : " + url);
				Log.i("snitzelhunt util",
						"Response Code : " + conn.getResponseCode());

				// get Server Response
				if (conn.getResponseCode() == 200) { // Successful
					// read Server Response => RouteInfo
					connIS = conn.getInputStream();
					String recv = ConnectionHelper.readResponse(connIS);

					RouteInfoContainer recRoute = GSonUtility
							.deserializeRouteInfoContainer(recv);
					resp.setRinfo(recRoute);
				}
				resp.setHttpStatus(conn.getResponseCode());
				return resp;

			} catch (IOException e) {
				ConnectionHelper.handleIOException(e);
			} finally {
				ConnectionHelper.cleanConnection(connIS, connOS, conn);
			}

			resp.setHttpStatus(-1);
			return resp;
		}

		protected void onPostExecute(Server_RouteInfo_ReadforUserResponse result) {
			target.processServer_RouteInfo_ReadforUser(result);
		}
	}

	/**
	 * AsyncTask to upload a Route to the remote mySQL Database.
	 * 
	 * @author jaschkowitz
	 * 
	 */
	private class UploadTask extends
			AsyncTask<Route, Void, Server_Route_CreateResponse> {
		private AsyncServer_Route_CreateResponse target;

		private UploadTask(AsyncServer_Route_CreateResponse targetAct) {
			super();
			target = targetAct;
		}

		@Override
		protected Server_Route_CreateResponse doInBackground(Route... route) {
			InputStream connIS = null;
			OutputStream connOS = null;
			HttpURLConnection conn = null;
			Server_Route_CreateResponse resp = new Server_Route_CreateResponse();

			try {
				// Setup for the Connection
				URL url = new URL("http://141.84.213.225:8080/MSP/uploadRoute");
				conn = ConnectionHelper.setupHttpConnection(url);

				// Connect
				conn.connect();

				// post Route to Server
				connOS = conn.getOutputStream();
				String json = GSonUtility.serializeRoute(route[0]);
				ConnectionHelper.writeString(connOS, json);

				Log.i("snitzelhunt util", "POST upload Route to URL : " + url);
				Log.i("snitzelhunt util",
						"Response Code : " + conn.getResponseCode());

				if (conn.getResponseCode() == 200) {
					connIS = conn.getInputStream();
					String recv = ConnectionHelper.readResponse(connIS);
					long routeID = GSonUtility.deserializeLong(recv);
					resp.setGlobalID(routeID);
				}
				resp.setHttpStatus(conn.getResponseCode());
				return resp;

			} catch (IOException e) {
				ConnectionHelper.handleIOException(e);
			} finally {
				ConnectionHelper.cleanConnection(connIS, connOS, conn);
			}
			resp.setHttpStatus(-1);
			return resp;
		}

		protected void onPostExecute(Server_Route_CreateResponse result) {
			target.processServer_Route_Create(result);
		}
	}

	/**
	 * AsyncTask to upload a Route to the remote mySQL Database.
	 * 
	 * @author jaschkowitz
	 * 
	 */
	private class UpdateTask extends
			AsyncTask<Route, Void, Server_Route_UpdateResponse> {
		private AsyncServer_Route_UpdateResponse target;

		private UpdateTask(AsyncServer_Route_UpdateResponse targetAct) {
			super();
			target = targetAct;
		}

		@Override
		protected Server_Route_UpdateResponse doInBackground(Route... route) {
			InputStream connIS = null;
			OutputStream connOS = null;
			HttpURLConnection conn = null;
			Server_Route_UpdateResponse resp = new Server_Route_UpdateResponse();

			try {
				// Setup for the Connection
				URL url = new URL("http://141.84.213.225:8080/MSP/changeRoute");
				conn = ConnectionHelper.setupHttpConnection(url);

				// Connect
				conn.connect();

				// post Route to Server
				connOS = conn.getOutputStream();
				String json = GSonUtility.serializeRoute(route[0]);
				ConnectionHelper.writeString(connOS, json);

				Log.i("snitzelhunt util", "POST update route to URL : " + url);
				Log.i("snitzelhunt util",
						"Response Code : " + conn.getResponseCode());

				resp.setHttpStatus(conn.getResponseCode());
				return resp;
			} catch (IOException e) {
				ConnectionHelper.handleIOException(e);
			} finally {
				ConnectionHelper.cleanConnection(connIS, connOS, conn);
			}
			resp.setHttpStatus(-1);
			return resp;
		}

		protected void onPostExecute(Server_Route_UpdateResponse result) {
			target.processServer_Route_Update(result);
		}
	}

	/**
	 * AsyncTask to get information about Routes from a Creator from the remote
	 * mySQL Database.
	 * 
	 * @author jaschkowitz
	 * 
	 */
	private class RouteInfoReadforCreatorTask extends
			AsyncTask<String, Void, Server_RouteInfo_ReadforCreatorResponse> {
		private AsyncServer_RouteInfo_ReadforCreatorResponse target;

		private RouteInfoReadforCreatorTask(
				AsyncServer_RouteInfo_ReadforCreatorResponse targetAct) {
			super();
			target = targetAct;
		}

		@Override
		protected Server_RouteInfo_ReadforCreatorResponse doInBackground(
				String... creator) {
			InputStream connIS = null;
			OutputStream connOS = null;
			HttpURLConnection conn = null;
			Server_RouteInfo_ReadforCreatorResponse resp = new Server_RouteInfo_ReadforCreatorResponse();

			try {
				// Setup for the Connection
				URL url = new URL(
						"http://141.84.213.225:8080/MSP/getCreatorRoute");
				conn = ConnectionHelper.setupHttpConnection(url);

				// Connect
				conn.connect();

				// post Userdata to Server
				connOS = conn.getOutputStream();
				String str = creator[0];
				ConnectionHelper.writeString(connOS, str);

				Log.i("snitzelhunt util", "POST read routeinfo to URL : " + url);
				Log.i("snitzelhunt util",
						"Response Code : " + conn.getResponseCode());

				// get Server Response
				if (conn.getResponseCode() == 200) { // Successful
					// read Server Response => RouteInfo
					connIS = conn.getInputStream();
					String recv = ConnectionHelper.readResponse(connIS);

					RouteInfoContainer recRoute = GSonUtility
							.deserializeRouteInfoContainer(recv);
					resp.setRinfo(recRoute);
				}
				resp.setHttpStatus(conn.getResponseCode());
				return resp;

			} catch (IOException e) {
				ConnectionHelper.handleIOException(e);
			} finally {
				ConnectionHelper.cleanConnection(connIS, connOS, conn);
			}

			resp.setHttpStatus(-1);
			return resp;
		}

		protected void onPostExecute(
				Server_RouteInfo_ReadforCreatorResponse result) {
			target.processServer_RouteInfo_ReadforCreator(result);
		}
	}
}
